package system

import (
	"fmt"
	"github.com/shirou/gopsutil/v3/process"
	"os"
	"strings"
)

// 获取指定应用的进程pid
// name: 进程名称或者 进程启动时候相关命令行参数
// 尽量使用范围大的这样才能精确匹配
// 比如: 语雀.exe --type=gpu-process --user-data-dir="C:\Users"
// 如果只传入 语雀 会匹配到很多进程
// 我们可以传入 语雀.exe --type=gpu-process --user
func GetPid(name string) []int32 {
	name = strings.ToLower(name)
	// 获取所有运行中的进程信息
	procs, err := process.Pids()
	if err != nil {
		fmt.Println("Error getting process list:", err)
	}
	var pids []int32
	// 遍历所有进程
	for _, pid := range procs {
		p, _ := process.NewProcess(pid)
		name1, _ := p.Name()
		name1 = strings.ToLower(name1)
		// 如果进程名称匹配，添加到pids列表中 ,不区分大小写
		if strings.Contains(name1, name) {
			pids = append(pids, pid)
			continue
		}
		// 如果进程命令行包含指定名称，添加到pids列表中 ,不区分大小写
		cmdline, _ := p.Cmdline()
		cmdline = strings.ToLower(cmdline)
		if strings.Contains(cmdline, name) {
			pids = append(pids, pid)
			continue
		}
	}
	return pids
}

// 杀死指定pid的进程
func KillPid(pid ...int32) error {
	for _, v := range pid {
		p, err := process.NewProcess(v)
		if err != nil {
			return err
		}
		err = p.Kill() //杀死进程
		if err != nil {
			return err
		}
	}
	return nil
}

// 获取进程的线程数
func GetProcessThreadCount(pid int32) int32 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	num, err := p.NumThreads()
	if err != nil {
		panic(err)
	}
	return num
}

// 获取进程的命令行参数
func GetProcessCmdline(pid int32) string {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	cmdline, err := p.Cmdline()
	if err != nil {
		panic(err)
	}
	return cmdline
}

// 获取进程的父进程pid
func GetProcessParent(pid int32) int32 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	ppid, err := p.Ppid()
	if err != nil {
		panic(err)
	}
	return ppid
}

// 获取进程的工作目录
func GetProcessCwd(pid int32) string {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	cwd, err := p.Cwd()
	if err != nil {
		panic(err)
	}
	return cwd
}

// 获取进程的创建时间 , 返回时间戳
func GetProcessCreateTime(pid int32) int64 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	createTime, err := p.CreateTime()
	if err != nil {
		panic(err)
	}
	return createTime
}

// 通过pid获取进程占用内存信息 (单位: MB)
func GetProcessRSS(pid int32) uint64 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	info, err := p.MemoryInfo()
	if err != nil {
		panic(err)
	}

	return info.RSS / 1024 / 1024
}

// 获取进程可执行文件路径
func GetProcessExe(pid int32) string {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	path, err := p.Exe()
	if err != nil {
		panic(err)
	}
	return path
}

// 获取进程的用户名
func GetProcessUsername(pid int32) string {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	username, err := p.Username()
	if err != nil {
		panic(err)
	}
	return username
}

// 获取进程的cpu占用率
func GetProcessCpuPercent(pid int32) float64 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	percent, err := p.CPUPercent()
	if err != nil {
		panic(err)
	}
	return percent
}

// 获取进程的内存占用率
func GetProcessMemPercent(pid int32) float32 {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	percent, err := p.MemoryPercent()
	if err != nil {
		panic(err)
	}
	return percent
}

// 获取进程的io信息
// 返回值: 从启动到现在累积的   读取次数, 写入次数,读取字节数, 写入字节数    (单位: MB)
func GetProcessIoInfo(pid int32) (uint64, uint64, uint64, uint64) {
	p, err := process.NewProcess(pid)
	if err != nil {
		panic(err)
	}
	io, err := p.IOCounters()
	if err != nil {
		panic(err)
	}
	return io.ReadCount, io.WriteCount, io.ReadBytes / 1024 / 1024, io.WriteBytes / 1024 / 1024
}

// 启动一个进程，返回进程id
func StartProcess(path string, args ...string) int {
	process, err := os.StartProcess(path, args, nil)
	if err != nil {
		fmt.Println("启动进程失败:", err)
		return -1
	}
	return process.Pid
}

// 等待一个进程结束，并返回进程的状态码
func WaitProcess(pid int) int {
	process, err := os.FindProcess(pid)
	if err != nil {
		fmt.Println("获取进程信息失败:", err)
		return -1
	}
	state, err1 := process.Wait()
	if err1 != nil {
		fmt.Println("等待进程失败:", err)
		return -1
	}
	return state.ExitCode()
}
